package bg.btanev.eightyfour.client.presenter;

import java.util.ArrayList;
import java.util.List;

import bg.btanev.eightyfour.client.service.GWTCommandServiceAsync;
import bg.btanev.eightyfour.shared.command.CommandResult;
import bg.btanev.eightyfour.shared.command.profile.DeleteProfileCommand;
import bg.btanev.eightyfour.shared.command.profile.FindProfilesCommand;
import bg.btanev.eightyfour.shared.command.profile.FindProfilesInput;
import bg.btanev.eightyfour.shared.command.profile.SaveProfileCommand;
import bg.btanev.eightyfour.shared.command.profile.UpdateProfileInput;
import bg.btanev.eightyfour.shared.dto.TargetDto;
import bg.btanev.eightyfour.shared.dto.profile.ProfileDto;
import bg.btanev.eightyfour.shared.dto.profile.ProfileEventDto;
import bg.btanev.eightyfour.shared.dto.profile.feed.FeedProfileDto;
import bg.btanev.eightyfour.shared.state.ProfileType;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasWidgets;

/**
 *
 * @author B.Tanev
 *
 */
public class ProfilesPresenter implements Presenter {

	public static interface ProfilesDisplay extends Display {
		ProfileType getSelectedType();

		ProfileDto<? extends ProfileEventDto> getSelectedProfile();

		HasClickHandlers getProfilesListbox();

		HasClickHandlers getAddNewButton();

		HasClickHandlers getSaveButton();

		HasClickHandlers getDeleteButton();

		HasText getNameData();

		HasText getUrlData();

		void clearView();

		boolean isValid();

		void setProfiles(List<? extends ProfileDto<? extends ProfileEventDto>> profiles);

		<P extends ProfileDto<? extends ProfileEventDto>> void setProfile(P profile);

		<P extends ProfileDto<? extends ProfileEventDto>> P getProfile();
	}

	@SuppressWarnings("unchecked")
	private final GWTCommandServiceAsync rpcService;
	private final ProfilesDisplay display;
	private final TargetDto target;

	@SuppressWarnings("unchecked")
	public ProfilesPresenter(GWTCommandServiceAsync rpcService, ProfilesDisplay display, TargetDto target) {
		super();

		this.rpcService = rpcService;
		this.display = display;
		this.target = target;

		this.display.getProfilesListbox().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ProfileDto<? extends ProfileEventDto> selProfile = ProfilesPresenter.this.display.getSelectedProfile();
				if (selProfile != null) {
					ProfilesPresenter.this.display.setProfile(selProfile);
				}
			}
		});

		final AsyncCallback<CommandResult<UpdateProfileInput, ArrayList<? extends ProfileDto<? extends ProfileEventDto>>>> updateProfileCallback = new AsyncCallback<CommandResult<UpdateProfileInput, ArrayList<? extends ProfileDto<? extends ProfileEventDto>>>>() {
			@Override
			public void onFailure(Throwable caught) {
				ProfilesPresenter.this.display.clearView();
			}

			@Override
			public void onSuccess(
					CommandResult<UpdateProfileInput, ArrayList<? extends ProfileDto<? extends ProfileEventDto>>> result) {

				if (result != null) {
					List<? extends ProfileDto<? extends ProfileEventDto>> profiles = result.getResult();
					ProfilesPresenter.this.display.setProfiles(profiles);
				}
			}
		};

		this.display.getSaveButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				if (!(ProfilesPresenter.this.display.isValid())) {
					return;
				}
				ProfileDto<? extends ProfileEventDto> profile = getDispayedProfileData();
				if (profile != null) {
					SaveProfileCommand command = new SaveProfileCommand();
					UpdateProfileInput input = new UpdateProfileInput();
					input.setProfile(profile);
					input.setTargetDto(ProfilesPresenter.this.target);
					command.setInput(input);

					ProfilesPresenter.this.rpcService.executeCommand(command, updateProfileCallback);
				}
			}
		});

		this.display.getDeleteButton().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ProfileDto<? extends ProfileEventDto> profile = getDispayedProfileData();
				if (profile != null && profile.getId() != null && profile.getId().longValue() > 0) {
					DeleteProfileCommand command = new DeleteProfileCommand();
					UpdateProfileInput input = new UpdateProfileInput();
					input.setProfile(profile);
					input.setTargetDto(ProfilesPresenter.this.target);
					command.setInput(input);

					ProfilesPresenter.this.rpcService.executeCommand(command, updateProfileCallback);
				}
			}
		});

		this.display.getAddNewButton().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ProfilesPresenter.this.display.setProfile(new FeedProfileDto());
			}
		});
	}

	private <P extends ProfileDto<? extends ProfileEventDto>> P getDispayedProfileData() {
		P profile = this.display.getProfile();

		if (profile != null) {
			profile.setName(display.getNameData().getText());
			profile.setType(display.getSelectedType());
			if (profile instanceof FeedProfileDto) {
				((FeedProfileDto) profile).setFeedUrl(display.getUrlData().getText());
			}
		}

		return profile;
	}

	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(display.asWidget());
		loadProfiles();
	}

	@SuppressWarnings("unchecked")
	private void loadProfiles() {
		display.clearView();

		FindProfilesCommand command = new FindProfilesCommand();
		FindProfilesInput input = new FindProfilesInput();
		input.setTargetDto(target);
		command.setInput(input);

		rpcService
				.executeCommand(
						command,
						new AsyncCallback<CommandResult<FindProfilesInput, ArrayList<? extends ProfileDto<? extends ProfileEventDto>>>>() {

							@Override
							public void onFailure(Throwable caught) {
								display.clearView();
							}

							@Override
							public void onSuccess(
									CommandResult<FindProfilesInput, ArrayList<? extends ProfileDto<? extends ProfileEventDto>>> result) {

								if (result != null) {
									List<? extends ProfileDto<? extends ProfileEventDto>> profiles = result.getResult();
									display.setProfiles(profiles);
								}
							}
						});
	}
}
